﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace LightFactory
{
    /// <summary>
    /// Shorter factory usage notation support
    /// </summary>
    public static class Factory<T>
    {
        /// <summary>
        /// Creates an instance of type T
        /// </summary>
        public static T Create()
        {
#if THROWABLE
            if (FactoryBase.GeneratorWrapper<T>.generator == null)
                throw new NullReferenceException("FactoryBase.GeneratorWrapper<" + typeof(T).Name + ">.generator not set");
            return FactoryBase.GeneratorWrapper<T>.generator();
#else
            return FactoryBase.GeneratorWrapper<T>.generator != null ?
                FactoryBase.GeneratorWrapper<T>.generator() : default(T);
#endif
        }

        /// <summary>
        /// Creates an instance of type T
        /// </summary>
        public static T Create<TParam1>(TParam1 param1)
        {
#if THROWABLE
            if (FactoryBase.GeneratorWrapper1<T, TParam1>.generator == null)
                throw new NullReferenceException("FactoryBase.GeneratorWrapper<" + typeof(T).Name + ", TParam1>.generator not set");
            return FactoryBase.GeneratorWrapper1<T, TParam1>.generator(param1);
#else
            return FactoryBase.GeneratorWrapper1<T, TParam1>.generator != null ? 
                FactoryBase.GeneratorWrapper1<T, TParam1>.generator(param1) : default(T);
#endif
        }

        /// <summary>
        /// Creates an instance of type T
        /// </summary>
        public static T Create<TParam1, TParam2>(TParam1 param1, TParam2 param2)
        {
#if THROWABLE
            if (FactoryBase.GeneratorWrapper2<T, TParam1, TParam2>.generator == null)
                throw new NullReferenceException("FactoryBase.GeneratorWrapper<" + typeof(T).Name + ">.generator not set");
            return FactoryBase.GeneratorWrapper2<T, TParam1, TParam2>.generator(param1, param2);
#else
            return FactoryBase.GeneratorWrapper2<T, TParam1, TParam2>.generator != null ? 
                FactoryBase.GeneratorWrapper2<T, TParam1, TParam2>.generator(param1, param2) : default(T);
#endif
        }

        /// <summary>
        /// Creates an instance of type T
        /// </summary>
        public static T Create<TParam1, TParam2, TParam3>(TParam1 param1, TParam2 param2, TParam3 param3)
        {
#if THROWABLE
            if (FactoryBase.GeneratorWrapper3<T, TParam1, TParam2, TParam3>.generator == null)
                throw new NullReferenceException("FactoryBase.GeneratorWrapper<" + typeof(T).Name + ">.generator not set");
            return FactoryBase.GeneratorWrapper3<T, TParam1, TParam2, TParam3>.generator(param1, param2, param3);
#else
            return FactoryBase.GeneratorWrapper3<T, TParam1, TParam2, TParam3>.generator != null ? 
                FactoryBase.GeneratorWrapper3<T, TParam1, TParam2, TParam3>.generator(param1, param2, param3) : default(T);
#endif
        }

        /// <summary>
        /// Creates an instance of type T
        /// </summary>
        public static T Create<TParam1, TParam2, TParam3, TParam4>(TParam1 param1, TParam2 param2, TParam3 param3, TParam4 param4)
        {
#if THROWABLE
            if (FactoryBase.GeneratorWrapper4<T, TParam1, TParam2, TParam3, TParam4>.generator == null)
                throw new NullReferenceException("FactoryBase.GeneratorWrapper<" + typeof(T).Name + ">.generator not set");
            return FactoryBase.GeneratorWrapper4<T, TParam1, TParam2, TParam3, TParam4>.generator(param1, param2, param3, param4);
#else
            return FactoryBase.GeneratorWrapper4<T, TParam1, TParam2, TParam3, TParam4>.generator != null ? 
                FactoryBase.GeneratorWrapper4<T, TParam1, TParam2, TParam3, TParam4>.generator(param1, param2, param3, param4) : default(T);
#endif
        }

        /// <summary>
        /// Return singleton instance of type T. Parameterless generator type T must be defined.
        /// </summary>
        public static T GetSingleton()
        {
#if THROWABLE
            if (FactoryBase.GeneratorWrapper<T>.SingleInstance == null)
            {
                if (FactoryBase.GeneratorWrapper<T>.generator == null)
                    throw new NullReferenceException("FactoryBase.GeneratorWrapper<" + typeof(T).Name + ">.generator not set");
                FactoryBase.GeneratorWrapper<T>.SingleInstance = FactoryBase.GeneratorWrapper<T>.generator();
            }
            return FactoryBase.GeneratorWrapper<T>.SingleInstance;
#else
            return FactoryBase.GeneratorWrapper<T>.SingleInstance!=null ? 
                FactoryBase.GeneratorWrapper<T>.SingleInstance
                : (FactoryBase.GeneratorWrapper<T>.SingleInstance = FactoryBase.GeneratorWrapper<T>.generator != null ?
                FactoryBase.GeneratorWrapper<T>.generator() : default(T));
#endif
        }
    }
}